#include "base.h"
#include <openssl/dsa.h>
#include "memreuse.h"
#include "randomnumber.h"

int main()
{
  RandomNumber rand;
  rand.Initialize(160);

  FILE * pfile = fopen("dsakey", "w+");
  DSA* dsa = DSA_generate_parameters(1024, NULL, 10, NULL, NULL, NULL, NULL);
  BN_print_fp(pfile, dsa->p);
  fprintf(pfile, "\n");
  BN_print_fp(pfile, dsa->q);
  fprintf(pfile, "\n");
  BN_print_fp(pfile, dsa->g);
  fprintf(pfile, "\n");
  fclose(pfile);
  //  BN_print_fp(pfile, dsa->priv_key);
  //   BN_print_fp(pfile, dsa->pub_key);
  pfile = fopen("dsakey", "r");
  mpz_t * p = Memreuse::New();
  mpz_t * q = Memreuse::New();
  mpz_t * g = Memreuse::New();
  gmp_fscanf(pfile, "%Zx\n", *p);
  gmp_fscanf(pfile, "%Zx\n", *q);
  gmp_fscanf(pfile, "%Zx\n", *g);
  fclose(pfile);

  // generate x, y
  mpz_t * x = Memreuse::New();
  mpz_t * y = Memreuse::New();
  rand.Get_Z_Range(x, q);
  mpz_powm(*y, *g, *x, *p);

  // store private key p, q, g, x
  pfile = fopen("dsa.priv", "w+");
  gmp_fprintf(pfile, "%Zx\n", *p);
  gmp_fprintf(pfile, "%Zx\n", *q);
  gmp_fprintf(pfile, "%Zx\n", *g);
  gmp_fprintf(pfile, "%Zx\n", *x);
  fclose(pfile);

  // store public key p, q, g, y
  pfile = fopen("dsa.pub", "w+");
  gmp_fprintf(pfile, "%Zx\n", *p);
  gmp_fprintf(pfile, "%Zx\n", *q);
  gmp_fprintf(pfile, "%Zx\n", *g);
  gmp_fprintf(pfile, "%Zx\n", *y);
  fclose(pfile);
  
  // verify
//   mpz_t * h = Memreuse::New();
//   mpz_t * a = Memreuse::New();
//   mpz_t * t1 = Memreuse::New();
//   mpz_t * t2 = Memreuse::New();

//   mpz_sub_ui(*t1, *p, 1);
//   if (mpz_divisible_p(*t1, *q))
//     {
//       printf("divisible\n");
//     }
//   mpz_divexact(*t2, *t1, *q);        // t2=(p-1)/q

//   mpz_set_ui(*h, 2);
//   //  mpz_powm(*h, *h, *t2, *p);    // h=h^t2 in G
//   rand.Get_Z_Range(a, q);       // a in [0, q)
//   mpz_powm(*t1, *g, *a, *p);    // t1=g^a
//   mpz_mul(*t1, *t1, *h);        // t1=t1*h
//   mpz_mod(*t1, *t1, *p);        
//   mpz_powm(*t1, *t1, *x, *p);   // t1=t1^x
//   mpz_invert(*t2, *y, *p);      // t2=y^-1
//   mpz_powm(*t2, *t2, *a, *p);   // t2=t2^a
//   mpz_mul(*t1, *t1, *t2);       // t1=t1*t2
//   mpz_mod(*t1, *t1, *p);
//   gmp_printf("%Zx\n", *t1);

//   mpz_powm(*t2, *h, *x, *p);    // t2=h^x
//   gmp_printf("%Zx\n", *t2);

  return 1;
}
